﻿#include "H264_Decoder.h"
#include "H264_Decoder.h"
#include "Video_Convert.h"
#include <QDebug>

H264_Decoder::H264_Decoder(AVContext* ac,QObject* parent)
    :QThread(parent)
    ,avContext_(ac)
{
    videoConver_ = new Video_Convert();
    yuv_frame_ = AVFramePtr(av_frame_alloc(), [](AVFrame* p) {av_frame_free(&p);});
}

int H264_Decoder::Open(const AVCodecParameters* codecParamer)
{
    if(is_initial_ || !codecParamer)
    {
        return -1;
    }
    codec_ = const_cast<AVCodec*>(avcodec_find_decoder(codecParamer->codec_id));
    if (!codec_) {
        qDebug() << "video avcodec_find_decoder failed.";
        return -1;
    }
    codecContext_ = avcodec_alloc_context3(codec_);
    if (avcodec_parameters_to_context(codecContext_,codecParamer) < 0) {
        qDebug() << "video avcodec_parameters_to_context failed.";
        return -1;
    }

    // 根据上下文配置视频解码器
    if (avcodec_open2(codecContext_, codec_, nullptr) != 0) {
        qDebug() << "avcodec_open2() failed.";
        return -1;
    }
    avContext_->video_width = codecContext_->width;
    avContext_->video_height = codecContext_->height;
    avContext_->video_fmt = AV_PIX_FMT_YUV420P;
    // 设置视频缩放转换器
    if(!videoConver_->Open(codecContext_->width,codecContext_->height,codecContext_->pix_fmt,
                           1080,600,AV_PIX_FMT_YUV420P))
    {
        qDebug() << "swsContext_ failed.";
        return -1;
    }
    is_initial_ = true;
    start();
    return 0;
}

void H264_Decoder::run()
{
    AVPacketPtr pkt = nullptr;
    while(!quit_ && videoConver_ && avContext_)
    {
        if(!video_queue_.size() || avContext_->video_queue_.size() > 100)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            continue;
        }
        video_queue_.pop(pkt);
        if (avcodec_send_packet(codecContext_, pkt.get())) {
            break;
        }
        int ret = 0;
        while (ret >= 0) {
            ret = avcodec_receive_frame(codecContext_, yuv_frame_.get());
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF || ret < 0)
                break;
            AVFramePtr outFrame = nullptr;
            //解码之后进行格式转换 将yuxxx
            if(videoConver_->Convert(yuv_frame_,outFrame))
            {
                if(outFrame)
                {
                    avContext_->video_queue_.push(outFrame);
                }
            }
        }
    }
}

void H264_Decoder::Close()
{
    quit_ = true;
    if(isRunning())
    {
        this->quit();
        this->wait();
    }
    if(videoConver_)
    {
        delete videoConver_;
        videoConver_ = nullptr;
    }
}


void H264_Decoder::Clear()
{
    std::lock_guard<std::mutex> lock(mutex_);
    avcodec_flush_buffers(codecContext_);
    video_queue_.clear();
}

void H264_Decoder::put_packet(const AVPacketPtr packet)
{
    video_queue_.push(packet);
}

H264_Decoder::~H264_Decoder()
{
    Close();
}

